package org.jeecg.modules.system.controller;

import cn.hutool.core.net.URLDecoder;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.symmetric.AES;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ccb.uass.client.bs.validation.ServiceTicketValiator;
import com.ccb.uass.client.cs.AuthException;
import com.ccb.uass.client.cs.UassClient;
import com.ccb.uass.client.cs.UassClientFactory;
import com.ccb.uass.client.cs.entity.Credential;
import com.ccb.uass.client.cs.entity.LoginType;
import com.ccb.uass.client.cs.entity.Principal;
import com.ccb.uass.client.cs.entity.Transaction;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.*;
//import org.jeecg.common.util.encryption.EncryptedString;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.model.SysLoginModel;
import org.jeecg.modules.system.model.SysUassTokenLoginModel;
import org.jeecg.modules.system.service.*;
import org.jeecg.modules.system.util.RandImageUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @Author scott
 * @since 2018-12-17
 */
@RestController
@RequestMapping("/sys")
@Api(tags = "用户登录")
@Slf4j
public class LoginController {
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private ISysBaseAPI sysBaseAPI;
    @Autowired
    private ISysLogService logService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ISysDepartService sysDepartService;
    @Autowired
    private ISysDictService sysDictService;
    @Resource
    private BaseCommonService baseCommonService;
    @Autowired
    private ISysRoleService sysRoleService;

    @Value("${spring.profiles.active}")
    private String profile;

    @Value("${uassLogin.superAdmin:}")
    private String uassSuperAdmin;

    @Value("${uassLogin.uassToken.aesKey:}")
    private String uassTokenAesKey;

    @Value("${uassLogin.uassToken.expire:600}")
    private Integer uassTokenExpire;

    //如果是接口应用则不允许登录
    @Value("${jeecg.enableLogin:true}")
    private Boolean enableLogin;

    private final String SUPER_ADMIN_USER = "superAdmin";

    private final String PREFIX_USER_UASS_TOKEN_KEY = "user:uass:loginToken:";

    @Autowired
    private ServiceTicketValiator serviceTicketValiator;

    private static final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
    private static final String RSA_LOGIN_PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALi76x5xV9b85q7qg11EhdsJyMDzklebSl+cPOZE+FaSaH0DJhcWRaWz31NtIV9fK8XXwcaFAWVEG/hdgXdLPhu8NwdXZhd3ySD7MfgJmFN+L2VmPjiUOG9x2vlLvnm9r1G/5jpP35e3FqBF3au8vXz59HP4GbLD+QRJ4d1y/tolAgMBAAECgYAG9RrgkWO9xtYYUeBDL7y72GU9cR76mjBlo/B+OqxAtHBnfuodFftnB3x6e6J1YVP4dk0HwUQhcHx+MOVanRSYbeuDWlFRE0uK/4I9gKpQznJfdwOlteWcbOQ5yDzEI2VMtQd9Qnx/CeJ1DRxG8PzvSRDG9tGnxorHIuPy7Mk4cQJBAOM5dQSv34y7IbwzaFQcYWVHXx63ddEFPZr9BML2FpA+CmWuGbpdfvCfir5iWn9XqkPwCKyWDn5xtt2Qwzu/FzECQQDQIO/Q1xueItb49eZZOHsHVWdK6Vi7papBNp2LmqKVc4zByVPMAs6n3niL1GexaxWVKIkajBxbC1eEoTD1Fp01AkAL6NgMTdeOvcQv5BXkyrQEJfCDYKRJN1gaRoa4XUOjfcz3tV9d2Eat//66qdcKc6LV+r/Jo/fQgs9N36eL+yERAkEAhqUoQHVJGq7zYDDFCudtQDtSDbaUfyEX2gSZO52YnRMZ9qxml88hHpzgY6XQR4k9dze4KwKFvajCv70ATS6KGQJARjQWl85IHMu33XCA1jTX3r8hHkZ94iHuK3ic/yU7+wBFsny3FsFZV1OdkoBMDTyfKLx9CwPIHaW+v4EMbVOasg==";


    @ApiOperation("登录接口")
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel) {
        Result<JSONObject> result = new Result<JSONObject>();
        if (enableLogin != null && enableLogin == false) {
            return result.error500("当前系统环境不允许登录");
        }

        String username = sysLoginModel.getUsername();
        String password = null;
        try {
            RSA rsa = new RSA(RSA_LOGIN_PRIVATE_KEY, null);
            password = rsa.decryptStr(sysLoginModel.getPassword(), KeyType.PrivateKey);
            if(password==null){
                return result.error500("登录密码不能为空");
            }
        } catch (Exception e) {
            log.error("密码解密出错，密文：{},错误信息:{}", sysLoginModel.getPassword(), e.getMessage());
            return result.error500("登录密码解密出错");
        }
        //update-begin--Author:scott  Date:20190805 for：暂时注释掉密码加密逻辑，有点问题
        //前端密码加密，后端进行密码解密
        //password = AesEncryptUtil.desEncrypt(sysLoginModel.getPassword().replaceAll("%2B", "\\+")).trim();//密码解密
        //update-begin--Author:scott  Date:20190805 for：暂时注释掉密码加密逻辑，有点问题

        //update-begin-author:taoyan date:20190828 for:校验验证码
        String captcha = sysLoginModel.getCaptcha();
        if (captcha == null) {
            result.error500("验证码不能为空");
            return result;
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        String realKey = MD5Util.MD5Encode(lowerCaseCaptcha + sysLoginModel.getCheckKey(), "utf-8");
        Object checkCode = redisUtil.get(realKey);
        //当进入登录页时，有一定几率出现验证码错误 #1714
        if (checkCode == null || !checkCode.toString().equals(lowerCaseCaptcha)) {
            result.error500("验证码错误");
            return result;
        }
        //update-end-author:taoyan date:20190828 for:校验验证码

        //1. 校验用户是否有效
        //update-begin-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug，if条件永远为false
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, username);
        SysUser sysUser = sysUserService.getOne(queryWrapper);
        //update-end-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug，if条件永远为false
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        //2. 校验用户名或密码是否正确
        String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
        String syspassword = sysUser.getPassword();
        if (!syspassword.equals(userpassword)) {
            result.error500("用户名或密码错误");
            return result;
        }

        //用户登录信息
        userInfo(sysUser, result);
        //update-begin--Author:liusq  Date:20210126  for：登录成功，删除redis中的验证码
        redisUtil.del(realKey);
        //update-begin--Author:liusq  Date:20210126  for：登录成功，删除redis中的验证码
        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(sysUser, loginUser);
        baseCommonService.addLog("用户名: " + username + ",登录成功！", CommonConstant.LOG_TYPE_1, null, loginUser);
        //update-end--Author:wangshuai  Date:20200714  for：登录日志没有记录人员
        return result;
    }

    /**
     * 退出登录
     *
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/logout")
    public Result<Object> logout(HttpServletRequest request, HttpServletResponse response) {
        //用户退出逻辑
        String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
        if (oConvertUtils.isEmpty(token)) {
            return Result.error("退出登录失败！");
        }
        String username = JwtUtil.getUsername(token);
        LoginUser sysUser = sysBaseAPI.getUserByName(username);
        if (sysUser != null) {
            //update-begin--Author:wangshuai  Date:20200714  for：登出日志没有记录人员
            baseCommonService.addLog("用户名: " + sysUser.getRealname() + ",退出成功！", CommonConstant.LOG_TYPE_1, null, sysUser);
            //update-end--Author:wangshuai  Date:20200714  for：登出日志没有记录人员
            log.info(" 用户名:  " + sysUser.getRealname() + ",退出成功！ ");
            //清空用户登录Token缓存
            redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
            //清空用户登录Shiro权限缓存
            redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
            //清空用户的缓存信息（包括部门信息），例如sys:cache:user::<username>
            redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
            //调用shiro的logout
            SecurityUtils.getSubject().logout();
            return Result.ok("退出登录成功！");
        } else {
            return Result.error("Token无效!");
        }
    }

    /**
     * 获取访问量
     *
     * @return
     */
    @GetMapping("loginfo")
    public Result<JSONObject> loginfo() {
        Result<JSONObject> result = new Result<JSONObject>();
        JSONObject obj = new JSONObject();
        //update-begin--Author:zhangweijian  Date:20190428 for：传入开始时间，结束时间参数
        // 获取一天的开始和结束时间
        Calendar calendar = new GregorianCalendar();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date dayStart = calendar.getTime();
        calendar.add(Calendar.DATE, 1);
        Date dayEnd = calendar.getTime();
        // 获取系统访问记录
        Long totalVisitCount = logService.findTotalVisitCount();
        obj.put("totalVisitCount", totalVisitCount);
        Long todayVisitCount = logService.findTodayVisitCount(dayStart, dayEnd);
        obj.put("todayVisitCount", todayVisitCount);
        Long todayIp = logService.findTodayIp(dayStart, dayEnd);
        //update-end--Author:zhangweijian  Date:20190428 for：传入开始时间，结束时间参数
        obj.put("todayIp", todayIp);
        result.setResult(obj);
        result.success("登录成功");
        return result;
    }

    /**
     * 获取访问量
     *
     * @return
     */
    @GetMapping("visitInfo")
    public Result<List<Map<String, Object>>> visitInfo() {
        Result<List<Map<String, Object>>> result = new Result<List<Map<String, Object>>>();
        Calendar calendar = new GregorianCalendar();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date dayEnd = calendar.getTime();
        calendar.add(Calendar.DAY_OF_MONTH, -7);
        Date dayStart = calendar.getTime();
        List<Map<String, Object>> list = logService.findVisitCount(dayStart, dayEnd);
        result.setResult(oConvertUtils.toLowerCasePageList(list));
        if(result== null){
            result.error500("未查询到数据");
        }
        return result;
    }


    /**
     * 登陆成功选择用户当前部门
     *
     * @param user
     * @return
     */
    @ApiOperation("登陆成功选择用户当前部门")
    @RequestMapping(value = "/selectDepart", method = RequestMethod.PUT)
    public Result<JSONObject> selectDepart(@RequestBody SysUser user) {
        Result<JSONObject> result = new Result<JSONObject>();
        String username = user.getUsername();
        if (oConvertUtils.isEmpty(username)) {
            LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
            username = sysUser.getUsername();
        }
        String orgCode = user.getOrgCode();
        this.sysUserService.updateUserDepart(username, orgCode);
        SysUser sysUser = sysUserService.getUserByName(username);
        JSONObject obj = new JSONObject();
        obj.put("userInfo", sysUser);
        result.setResult(obj);
        return result;
    }

    /**
     * 短信登录接口
     *
     * @param jsonObject
     * @return
     */
    @ApiOperation("手机号模式")
    @PostMapping(value = "/sms")
    public Result<String> sms(@RequestBody JSONObject jsonObject) {
        Result<String> result = new Result<String>();
        String mobile = jsonObject.get("mobile").toString();
        //手机号模式 登录模式: "2"  注册模式: "1"
        String smsmode = jsonObject.get("smsmode").toString();
        log.info(mobile);
        if (oConvertUtils.isEmpty(mobile)) {
            result.setMessage("手机号不允许为空！");
            result.setSuccess(false);
            return result;
        }
        Object object = redisUtil.get(mobile);
        if (object != null) {
            result.setMessage("验证码10分钟内，仍然有效！");
            result.setSuccess(false);
            return result;
        }

        //随机数
        String captcha = RandomUtil.randomNumbers(6);
        JSONObject obj = new JSONObject();
        obj.put("code", captcha);
        try {
            boolean b = false;
            //注册模板
            if (CommonConstant.SMS_TPL_TYPE_1.equals(smsmode)) {
                SysUser sysUser = sysUserService.getUserByPhone(mobile);
                if (sysUser != null) {
                    result.error500(" 手机号已经注册，请直接登录！");
                    baseCommonService.addLog("手机号已经注册，请直接登录！", CommonConstant.LOG_TYPE_1, null);
                    return result;
                }
                b = DySmsHelper.sendSms(mobile, obj, DySmsEnum.REGISTER_TEMPLATE_CODE);
            } else {
                //登录模式，校验用户有效性
                SysUser sysUser = sysUserService.getUserByPhone(mobile);
                result = sysUserService.checkUserIsEffective(sysUser);
                if (!result.isSuccess()) {
                    String message = result.getMessage();
                    if ("该用户不存在，请注册".equals(message)) {
                        result.error500("该用户不存在或未绑定手机号");
                    }
                    return result;
                }

                /**
                 * smsmode 短信模板方式  0 .登录模板、1.注册模板、2.忘记密码模板
                 */
                if (CommonConstant.SMS_TPL_TYPE_0.equals(smsmode)) {
                    //登录模板
                    b = DySmsHelper.sendSms(mobile, obj, DySmsEnum.LOGIN_TEMPLATE_CODE);
                } else if (CommonConstant.SMS_TPL_TYPE_2.equals(smsmode)) {
                    //忘记密码模板
                    b = DySmsHelper.sendSms(mobile, obj, DySmsEnum.FORGET_PASSWORD_TEMPLATE_CODE);
                }
            }

            if (b == false) {
                result.setMessage("短信验证码发送失败,请稍后重试");
                result.setSuccess(false);
                return result;
            }
            //验证码10分钟内有效
            redisUtil.set(mobile, captcha, 600);
            //update-begin--Author:scott  Date:20190812 for：issues#391
            //result.setResult(captcha);
            //update-end--Author:scott  Date:20190812 for：issues#391
            result.setSuccess(true);

        } catch (ClientException e) {
            e.printStackTrace();
            result.error500(" 短信接口未配置，请联系管理员！");
            return result;
        }
        return result;
    }


    /**
     * 手机号登录接口
     *
     * @param jsonObject
     * @return
     */
    @ApiOperation("手机号登录接口")
    @PostMapping("/phoneLogin")
    public Result<JSONObject> phoneLogin(@RequestBody JSONObject jsonObject) {
        Result<JSONObject> result = new Result<JSONObject>();
        if (enableLogin != null && enableLogin == false) {
            return result.error500("当前系统环境不允许登录");
        }

        String phone = jsonObject.getString("mobile");
        //校验用户有效性
        SysUser sysUser = sysUserService.getUserByPhone(phone);
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        String smscode = jsonObject.getString("captcha");
        Object code = redisUtil.get(phone);
        if (!smscode.equals(code)) {
            result.setMessage("手机验证码错误");
            return result;
        }
        //用户信息
        userInfo(sysUser, result);
        //添加日志
        baseCommonService.addLog("用户名: " + sysUser.getUsername() + ",登录成功！", CommonConstant.LOG_TYPE_1, null);

        return result;
    }

    @ApiOperation("uass单点登录接口")
    @PostMapping("/uassLogin")
    public Result<?> uassLogin(HttpServletRequest req, @RequestBody SysLoginModel sysLoginModel) {
        Result<JSONObject> result = new Result<JSONObject>();
        if (enableLogin != null && enableLogin == false) {
            return result.error500("当前系统环境不允许登录");
        }

        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();

        //开发环境不能调通uass，只有生产环境才调
        if("prod".equals(profile)) {
            UassClient uc = UassClientFactory.client();
            String ipAddr2 = null;
            try {
                InetAddress addr = InetAddress.getLocalHost();
                ipAddr2 = new String(addr.getHostAddress());
            } catch (UnknownHostException e) {
                log.error("获取当前服务器IP失败", e.getMessage());
                throw new JeecgBootException("获取当前服务器IP失败");
            }
            Credential cred = new Credential();
            cred.setTransaction(Transaction.AUTH_PASSWORDD);
            cred.setLoginName(username);
            cred.setSecVoucher(password);
            cred.setLoginType(LoginType.LOGIN_NAME);
            cred.setClientIp(ipAddr2);
            try {
                Principal p = uc.login(cred);
                username = p.getUserName();
            } catch (AuthException e) {
                log.error("uass（静态密码）登录出错:" + e.getReturnCode() + e.getMessage(), e);
                return result.error500("uass密码方式登录出错:" + e.getReturnCode() + e.getMessage());
            }
        }

        if (StringUtils.isNotBlank(uassSuperAdmin)) {
            //多个用户
            String[] admins = uassSuperAdmin.split(",");
            if (admins.length > 1) {
                List<String> adminList = Arrays.asList(admins);
                if (adminList.contains(username)) {
                    username = SUPER_ADMIN_USER;
                }
            } else if (uassSuperAdmin.equals(username)) {
                username = SUPER_ADMIN_USER;
            }
        }
        log.error("uass登录成功，用户名为：" + username);

        //1. 校验用户是否有效
        //update-begin-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug，if条件永远为false
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, username);
        SysUser sysUser = sysUserService.getOne(queryWrapper);
        //update-end-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug，if条件永远为false
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        //因为uass只有生产环境才能通，开发和预生产直接跳过
        if("local".equals(profile) || "dev".equals(profile) || "pre".equals(profile)) {
            //2. 校验用户名或密码是否正确
//            String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
//            String syspassword = sysUser.getPassword();
//            if (!syspassword.equals(userpassword)) {
//                result.error500("用户名或密码错误");
//                return result;
//            }
        }


        //uass登录方式，如果用户没有设置密码，则直接生产成一随机密码。
        String tempPwd = PasswordUtil.getRanddomPsw(16);
        redisUtil.setString(CommonConstant.PREFIX_USER_UASS_REDISKEY + username, tempPwd, JwtUtil.EXPIRE_TIME * 2/ 1000);

        //用户登录信息
        userInfo(sysUser, tempPwd, CommonConstant.LOGIN_TYPE_UASS, result);

        //将token对应的加解密密钥放于redis
        Object token = result.getResult().get("token");
        redisUtil.setString(CommonConstant.PREFIX_USER_UASS_REDISKEY + token.toString(), tempPwd, JwtUtil.EXPIRE_TIME * 2/ 1000);

        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(sysUser, loginUser);
        baseCommonService.addLog("用户名: " + username + "(uass方式),登录成功！", CommonConstant.LOG_TYPE_1, null, loginUser);
        return result;
    }

    @ApiOperation("uass token单点登录接口")
    @PostMapping("/uassTokenLogin")
    public Result<?> uassStLogin(HttpServletRequest req, @Validated @RequestBody SysUassTokenLoginModel sysLoginModel) {
        Result<JSONObject> result = new Result<JSONObject>();
        String uassLoginToken = sysLoginModel.getToken();
        if (StringUtils.isBlank(uassTokenAesKey)) {
            return result.error500("系统未配置uass单点登录，请与系统管理员联系。");
        }
        uassLoginToken = new String(URLDecoder.decode(uassLoginToken.getBytes(StandardCharsets.UTF_8)));
        if (redisUtil.hasKey(PREFIX_USER_UASS_TOKEN_KEY + uassLoginToken)) {
            return result.error500("token已过期或已使用，请重新登录");
        }

        String username = null;
        try {
            String dencrypt = new String(new AES(uassTokenAesKey.getBytes()).decrypt(uassLoginToken));
            String timestamp = dencrypt.substring(0, 17);
            username = dencrypt.substring(17);
            //判断timestamp是否过期
            Date time = DateUtils.parseDate(timestamp, "yyyyMMddHHmmssSSS");
            long interval = (System.currentTimeMillis() - time.getTime()) / 1000;
            if (interval >= uassTokenExpire) {
                return result.error500("token已过期，请重新登录");
            }
        } catch (Exception e) {
            log.error("解密uass单点登录token【{}】出错", uassLoginToken, e);
            return result.error500("解析uass单点登录token出错，" + e.getMessage());
        }

        log.error("uass用户名为：" + username);
        if (StringUtils.isNotBlank(uassSuperAdmin)) {
            //多个用户
            String[] admins = uassSuperAdmin.split(",");
            if (admins.length > 1) {
                List<String> adminList = Arrays.asList(admins);
                if (adminList.contains(username)) {
                    username = SUPER_ADMIN_USER;
                }
            } else if (uassSuperAdmin.equals(username)) {
                username = SUPER_ADMIN_USER;
            }
        }
        log.error("用户名为：" + username);

        //1. 校验用户是否有效
        //update-begin-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug，if条件永远为false
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, username);
        SysUser sysUser = sysUserService.getOne(queryWrapper);
        //update-end-author:wangshuai date:20200601 for: 登录代码验证用户是否注销bug，if条件永远为false
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        //uass登录方式，如果用户没有设置密码，则直接生产成一随机密码。
        String tempPwd = PasswordUtil.getRanddomPsw(16);
        redisUtil.setString(CommonConstant.PREFIX_USER_UASS_REDISKEY + username, tempPwd, JwtUtil.EXPIRE_TIME * 2/ 1000);

        //用户登录信息
        userInfo(sysUser, tempPwd, CommonConstant.LOGIN_TYPE_UASS, result);

        //将token对应的加解密密钥放于redis
        Object token = result.getResult().get("token");
        redisUtil.setString(CommonConstant.PREFIX_USER_UASS_REDISKEY + token.toString(), tempPwd, JwtUtil.EXPIRE_TIME * 2/ 1000);

        LoginUser loginUser = new LoginUser();
        BeanUtils.copyProperties(sysUser, loginUser);
        baseCommonService.addLog("用户名: " + username + "(uass方式),登录成功！", CommonConstant.LOG_TYPE_1, null, loginUser);

        redisUtil.setString(PREFIX_USER_UASS_TOKEN_KEY + uassLoginToken, "1", uassTokenExpire);
        return result;
    }

    /**
     * 用户信息。（额外传密码和登录类型，兼容其他没有设置用户密码的方式登录）
     * @param sysUser
     * @param password
     * @param loginType
     * @param result
     * @return
     */
    private Result<JSONObject> userInfo(SysUser sysUser, String password, String loginType, Result<JSONObject> result) {
        String syspassword = password;
        if (StringUtils.isBlank(syspassword)) {
            syspassword = sysUser.getPassword();
        }
        String username = sysUser.getUsername();
        // 生成token
        String token = null;
        if (StringUtils.isBlank(loginType)) {
            token = JwtUtil.sign(username, syspassword);
        } else {
            token = JwtUtil.sign(username, syspassword, loginType);
        }
        // 设置token缓存有效时间
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);

        Set<String> userRolesSet = sysUserService.getUserRolesSet(username);
        JSONObject obj = new JSONObject();
        if (!userRolesSet.contains("superAdmin")) {
            // 获取用户部门信息
            List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
            obj.put("departs", departs);
            if (departs == null || departs.size() == 0) {
                obj.put("multi_depart", 0);
            } else if (departs.size() == 1) {
                sysUserService.updateUserDepart(username, departs.get(0).getOrgCode());
                obj.put("multi_depart", 1);
            } else {
                //查询当前是否有登录部门
                // update-begin--Author:wangshuai Date:20200805 for：如果用戶为选择部门，数据库为存在上一次登录部门，则取一条存进去
                SysUser sysUserById = sysUserService.getById(sysUser.getId());
                if (oConvertUtils.isEmpty(sysUserById.getOrgCode())) {
                    sysUserService.updateUserDepart(username, departs.get(0).getOrgCode());
                }
                // update-end--Author:wangshuai Date:20200805 for：如果用戶为选择部门，数据库为存在上一次登录部门，则取一条存进去
                obj.put("multi_depart", 2);
            }
        } else {
            sysUser.setRoleName("superAdmin");
        }
        obj.put("token", token);
        obj.put("userInfo", sysUser);
        obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
        result.setResult(obj);
        result.success("登录成功");
        return result;
    }

    /**
     * 用户信息
     *
     * @param sysUser
     * @param result
     * @return
     */
    private Result<JSONObject> userInfo(SysUser sysUser, Result<JSONObject> result) {
        return userInfo(sysUser, null, null, result);
    }

    /**
     * 获取加密字符串
     *
     * @return
     */
//    @GetMapping(value = "/getEncryptedString")
//    public Result<Map<String, String>> getEncryptedString() {
//        Result<Map<String, String>> result = new Result<Map<String, String>>();
//        Map<String, String> map = new HashMap<String, String>();
//        map.put("key", EncryptedString.key);
//        map.put("iv", EncryptedString.iv);
//        result.setResult(map);
//        return result;
//    }

    /**
     * 后台生成图形验证码 ：有效
     *
     * @param response
     * @param key
     */
    @ApiOperation("获取验证码")
    @GetMapping(value = "/randomImage/{key}")
    public Result<String> randomImage(HttpServletResponse response, @PathVariable String key) {
        Result<String> res = new Result<String>();
        try {
            String code = RandomUtil.randomString(BASE_CHECK_CODES, 4);
            String lowerCaseCode = code.toLowerCase();
            String realKey = MD5Util.MD5Encode(lowerCaseCode + key, "utf-8");
            redisUtil.set(realKey, lowerCaseCode, 60);
            String base64 = RandImageUtil.generate(code);
            res.setSuccess(true);
            res.setResult(base64);
        } catch (Exception e) {
            res.error500("获取验证码出错" + e.getMessage());
            e.printStackTrace();
        }
        return res;
    }

    /**
     * app登录
     *
     * @param sysLoginModel
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/mLogin", method = RequestMethod.POST)
    public Result<JSONObject> mLogin(@RequestBody SysLoginModel sysLoginModel) throws Exception {
        Result<JSONObject> result = new Result<JSONObject>();
        String username = sysLoginModel.getUsername();
        String password = sysLoginModel.getPassword();

        //1. 校验用户是否有效
        SysUser sysUser = sysUserService.getUserByName(username);
        result = sysUserService.checkUserIsEffective(sysUser);
        if (!result.isSuccess()) {
            return result;
        }

        //2. 校验用户名或密码是否正确
        String userpassword = PasswordUtil.encrypt(username, password, sysUser.getSalt());
        String syspassword = sysUser.getPassword();
        if (!syspassword.equals(userpassword)) {
            result.error500("用户名或密码错误");
            return result;
        }

        String orgCode = sysUser.getOrgCode();
        if (oConvertUtils.isEmpty(orgCode)) {
            //如果当前用户无选择部门 查看部门关联信息
            List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
            if (departs == null || departs.size() == 0) {
                result.error500("用户暂未归属部门,不可登录!");
                return result;
            }
            orgCode = departs.get(0).getOrgCode();
            sysUser.setOrgCode(orgCode);
            this.sysUserService.updateUserDepart(username, orgCode);
        }
        JSONObject obj = new JSONObject();
        //用户登录信息
        obj.put("userInfo", sysUser);

        // 生成token
        String token = JwtUtil.sign(username, syspassword);
        // 设置超时时间
        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);

        //token 信息
        obj.put("token", token);
        result.setResult(obj);
        result.setSuccess(true);
        result.setCode(200);
        baseCommonService.addLog("用户名: " + username + ",登录成功[移动端]！", CommonConstant.LOG_TYPE_1, null);
        return result;
    }

    /**
     * 图形验证码
     *
     * @param sysLoginModel
     * @return
     */
    @RequestMapping(value = "/checkCaptcha", method = RequestMethod.POST)
    public Result<?> checkCaptcha(@RequestBody SysLoginModel sysLoginModel) {
        String captcha = sysLoginModel.getCaptcha();
        String checkKey = sysLoginModel.getCheckKey();
        if (captcha == null) {
            return Result.error("验证码无效");
        }
        String lowerCaseCaptcha = captcha.toLowerCase();
        String realKey = MD5Util.MD5Encode(lowerCaseCaptcha + checkKey, "utf-8");
        Object checkCode = redisUtil.get(realKey);
        if (checkCode == null || !checkCode.equals(lowerCaseCaptcha)) {
            return Result.error("验证码错误");
        }
        return Result.ok();
    }

}
